﻿using System.Collections;
using Basic.FormCollect;
using Basic.FormCollect.Model;
using Basic.FormModel.PageLayout;
using Basic.FormModel.QueryColumn;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.PageCalculate.Model;
using Basic.FormRemoteModel.PageLayout.Chart;
using Basic.FormRemoteModel.PageLayout.Model;
using Basic.UserFormService.Interface;
using Basic.UserFormService.Model;
using SqlSugar;
using WeDonekRpc.CacheClient.Interface;
using WeDonekRpc.Helper;
using WeDonekRpc.SqlSugar.VirtualQuery;

namespace Basic.UserFormService.PageControl
{
    internal class ChartBodyCache
    {
        public ChartBody Result { get; set; }

        public HavingColumn Having { get; set; }
        /// <summary>
        /// 筛选条件
        /// </summary>
        public PageFilterParam[] Where { get; set; }
    }
    internal class PageChartService : PageControlService, IPageChartService
    {
        private readonly ICustomPageLayoutCollect _Layout;
        private readonly IPhysicsQueryBodyCollect _QueryTable;
        private readonly ILocalCacheController _Cache;

        public PageChartService ( ICustomPageLayoutCollect layout,
            ICustomPageCollect page,
            ILocalCacheController cache,
            IPhysicsQueryBodyCollect queryTable )
        {
            this._Cache = cache;
            this._Layout = layout;
            this._QueryTable = queryTable;
        }
        private ChartControl _Control;

        private PageGroupCol[] _GroupByCol;

        private readonly List<Segment> _ColName = new List<Segment>();

        public ChartBody Get ( long controlId, long companyId, Dictionary<string, string> extend )
        {
            string key = "ChartBody_" + controlId;
            if ( !this._Cache.TryGet(key, out ChartBodyCache body) )
            {
                body = this._GetChartBody(controlId);
                _ = this._Cache.Add(key, body, new TimeSpan(23, 0, 0));
            }
            if ( body.Result.Query == null )
            {
                return body.Result;
            }
            ChartBody res = body.Result.Clone();
            res.Query.Having = _InitHaving(body, extend);
            if ( !body.Where.IsNull() )
            {
                res.Query.Where = body.Where.GetWhere(body.Result.Cols, companyId, extend);
            }
            return res;
        }
        private ChartBodyCache _GetChartBody ( long controlId )
        {
            PageLayoutDto layout = this._Layout.Get<PageLayoutDto>(controlId);
            if ( layout.ControlType != PageControlType.图表 )
            {
                throw new ErrorException("form.page.control.type.error");
            }
            this._Control = layout.ControlConfig?.Chart;
            if ( !this._Control.Selects.IsNull() && !this._Control.GroupBy.IsNull() )
            {
                PhysicsFormBody body = this._QueryTable.Get(this._Control.FormId.Value);
                long[] tableId = this._GetTableId();
                base._InitTable(body, tableId);
                this._InitGroupBy();
                this._InitSelect();
            }
            return new ChartBodyCache
            {
                Having = this._Control.Having,
                Where = this._Control.Where,
                Result = new ChartBody
                {
                    Id = controlId,
                    FormId = this._Control.FormId,
                    PageId = layout.PageId,
                    ChartType = this._Control.ChartType,
                    Query = this._Query,
                    GroupByCol = this._GroupByCol,
                    Cols = this._Cols,
                    Segment = this._ColName.ToArray(),
                }
            };
        }
        private long[] _GetTableId ()
        {
            if ( this._Control.Where.IsNull() )
            {
                return this._Control.Selects.Select(c => c.TableId).Distinct().ToArray();
            }
            List<long> ids = this._Control.Selects.Select(a => a.TableId).ToList();
            this._Control.Where.ForEach(c =>
            {
                if ( c.Children.IsNull() )
                {
                    if ( c.TableId.HasValue )
                    {
                        ids.Add(c.TableId.Value);
                    }
                }
                else
                {
                    c.Children.ForEach(c =>
                    {
                        if ( c.TableId.HasValue )
                        {
                            ids.Add(c.TableId.Value);
                        }
                    });
                }
            });
            return ids.Distinct().ToArray();
        }
        private void _InitGroupBy ()
        {
            this._GroupByCol = new PageGroupCol[this._Control.GroupBy.Length];
            this._Query.GroupBy = this._Control.GroupBy.ConvertAll(( c, i ) =>
            {
                PhysicsQueryColumn col = this._column[c];
                PageGroupCol t = new PageGroupCol
                {
                    Id = col.Id,
                    Name = col.ColName,
                    Label = col.ColLabel,
                    TableId = col.TableId,
                    FuncType = col.FuncType,
                };
                if ( col.FuncType == FormColumnFuncType.选项值 && col.ColumnSet.TryGetValue("Items", out object val) )
                {
                    IList itemList = (IList)val;
                    t.Items = new Dictionary<string, string>();
                    foreach ( IDictionary<string, object> k in itemList )
                    {
                        object v = k["value"];
                        t.Items.Add(v == null ? null : Convert.ToString(v), Convert.ToString(k["text"]));
                    }
                }
                else if ( col.FuncType == FormColumnFuncType.字典项 || col.FuncType == FormColumnFuncType.树形字典 )
                {
                    t.DicId = col.DictId;
                }
                this._GroupByCol[i] = t;
                return new GroupByStruct
                {
                    Name = col.ColName,
                    Table = this._table[col.TableId].TableName
                };
            });
        }
        private void _InitSelect ()
        {
            List<SelectStruct> selects = new List<SelectStruct>(this._GroupByCol.Length + this._Control.Selects.Length);
            this._GroupByCol.ForEach(c =>
            {
                selects.Add(new SelectStruct
                {
                    Name = c.Name,
                    Func = QueryFuncType.None,
                    Table = this._table[c.TableId].TableName
                });
            });
            this._Control.Selects.ForEach(c =>
             {
                 PhysicsQueryColumn col = this._column[c.ColumnId];
                 this._ColName.Add(new Segment
                 {
                     Id = col.Id,
                     Key = c.Alias.IsNull() ? col.ColName : c.Alias,
                     Value = c.Label
                 });
                 selects.Add(new SelectStruct
                 {
                     Name = col.ColName,
                     Func = c.FuncType.GetQueryFuncType(out string format, out DateType? dateType),
                     DateType = dateType,
                     Format = format,
                     Table = this._table[col.TableId].TableName,
                     Alias = c.Alias
                 });
             });
            this._Query.Select = selects.ToArray();
        }
        private static HavingCol? _InitHaving ( ChartBodyCache body, Dictionary<string, string> extend )
        {
            if ( body.Having == null )
            {
                return null;
            }
            HavingColumn c = body.Having;
            ColTable col = body.Result.Cols[c.ColId];
            return new HavingCol
            {
                DbType = col.DataType.GetDbType(),
                ConditionalType = c.Mode.GetConditionalType(),
                Name = col.Name,
                Table = col.Table.Table,
                Value = c.Value.GetFilterValue(extend),
                Func = c.FuncType.GetQueryFuncType(out string format, out DateType? dateType),
                DateType = dateType,
                Format = format,
            };
        }
    }
}
